home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / mac / files / t_sys5 / 92052tar.gz / 920528.tar / arp.c < prev    next >
C/C++ Source or Header  |  1992-05-26  |  9KB  |  315 lines

  1. /* @(#) $Header: arp.c,v 1.10 92/05/26 10:08:48 deyke Exp $ */
  2.  
  3. /* Address Resolution Protocol (ARP) functions. Sits between IP and
  4.  * Level 2, mapping IP to Level 2 addresses for all outgoing datagrams.
  5.  * Copyright 1991 Phil Karn, KA9Q
  6.  */
  7. #include "global.h"
  8. #include "mbuf.h"
  9. #include "timer.h"
  10. #include "iface.h"
  11. #include "enet.h"
  12. #include "ax25.h"
  13. #include "icmp.h"
  14. #include "ip.h"
  15. #include "arp.h"
  16. #include "icmp.h"
  17.  
  18. static void arp_output __ARGS((struct iface *iface,int hardware,int32 target));
  19.  
  20. /* Hash table headers */
  21. struct arp_tab *Arp_tab[HASHMOD];
  22.  
  23. struct arp_stat Arp_stat;
  24.  
  25. /* Resolve an IP address to a hardware address; if not found,
  26.  * initiate query and return NULLCHAR.  If an address is returned, the
  27.  * interface driver may send the packet; if NULLCHAR is returned,
  28.  * res_arp() will have saved the packet on its pending queue,
  29.  * so no further action (like freeing the packet) is necessary.
  30.  */
  31. char *
  32. res_arp(iface,hardware,target,bp)
  33. struct iface *iface;    /* Pointer to interface block */
  34. int16 hardware;         /* Hardware type */
  35. int32 target;           /* Target IP address */
  36. struct mbuf *bp;        /* IP datagram to be queued if unresolved */
  37. {
  38.     register struct arp_tab *arp;
  39.     struct ip ip;
  40.  
  41.     if((arp = arp_lookup(hardware,target)) != NULLARP && arp->state == ARP_VALID)
  42.         return arp->hw_addr;
  43.     if(arp != NULLARP){
  44.         /* Earlier packets are already pending, kick this one back
  45.          * as a source quench
  46.          */
  47.         ntohip(&ip,&bp);
  48.         icmp_output(&ip,bp,ICMP_QUENCH,0,NULL);
  49.         free_p(bp);
  50.     } else {
  51.         /* Create an entry and put the datagram on the
  52.          * queue pending an answer
  53.          */
  54.         arp = arp_add(target,hardware,NULLCHAR,0);
  55.         enqueue(&arp->pending,bp);
  56.         arp_output(iface,hardware,target);
  57.     }
  58.     return NULLCHAR;
  59. }
  60. /* Handle incoming ARP packets. This is almost a direct implementation of
  61.  * the algorithm on page 5 of RFC 826, except for:
  62.  * 1. Outgoing datagrams to unresolved addresses are kept on a queue
  63.  *    pending a reply to our ARP request.
  64.  * 2. The names of the fields in the ARP packet were made more mnemonic.
  65.  * 3. Requests for IP addresses listed in our table as "published" are
  66.  *    responded to, even if the address is not our own.
  67.  */
  68. void
  69. arp_input(iface,bp)
  70. struct iface *iface;
  71. struct mbuf *bp;
  72. {
  73.     struct arp arp;
  74.     struct arp_tab *ap;
  75.     struct arp_type *at;
  76.     int i;
  77.  
  78.     Arp_stat.recv++;
  79.     if(ntoharp(&arp,&bp) == -1)     /* Convert into host format */
  80.         return;
  81.     if(arp.hardware >= NHWTYPES){
  82.         /* Unknown hardware type, ignore */
  83.         Arp_stat.badtype++;
  84.         return;
  85.     }
  86.     at = &Arp_type[arp.hardware];
  87.     if(arp.protocol != at->iptype){
  88.         /* Unsupported protocol type, ignore */
  89.         Arp_stat.badtype++;
  90.         return;
  91.     }
  92.     if(uchar(arp.hwalen) > MAXHWALEN || uchar(arp.pralen) != sizeof(int32)){
  93.         /* Incorrect protocol addr length (different hw addr lengths
  94.          * are OK since AX.25 addresses can be of variable length)
  95.          */
  96.         Arp_stat.badlen++;
  97.         return;
  98.     }
  99.     if(arp.sprotaddr == 0L || arp.tprotaddr == 0L) {
  100.         /* We are going to dead-end references for [0.0.0.0], since
  101.          * experience shows that these cause total lock up -- N1BEE
  102.          */
  103.         Arp_stat.badaddr++;
  104.         return;
  105.     }
  106.     if(memcmp(arp.shwaddr,at->bdcst,at->hwalen) == 0){
  107.         /* This guy is trying to say he's got the broadcast address! */
  108.         Arp_stat.badaddr++;
  109.         return;
  110.     }
  111.     /* If this guy is already in the table, update its entry
  112.      * unless it's a manual entry (noted by the lack of a timer)
  113.      */
  114.     ap = NULLARP;   /* ap plays the role of merge_flag in the spec */
  115.     if((ap = arp_lookup(arp.hardware,arp.sprotaddr)) != NULLARP
  116.      && dur_timer(&ap->timer) != 0){
  117.         ap = arp_add(arp.sprotaddr,arp.hardware,arp.shwaddr,0);
  118.     }
  119.     /* See if we're the address they're looking for */
  120.     if(ismyaddr(arp.tprotaddr) != NULLIF){
  121.         if(ap == NULLARP)       /* Only if not already in the table */
  122.             arp_add(arp.sprotaddr,arp.hardware,arp.shwaddr,0);
  123.  
  124.         if(arp.opcode == ARP_REQUEST){
  125.             /* Swap sender's and target's (us) hardware and protocol
  126.              * fields, and send the packet back as a reply
  127.              */
  128.             memcpy(arp.thwaddr,arp.shwaddr,(int16)uchar(arp.hwalen));
  129.             /* Mark the end of the sender's AX.25 address
  130.              * in case he didn't
  131.              */
  132.             if(arp.hardware == ARP_AX25)
  133.                 arp.thwaddr[uchar(arp.hwalen)-1] |= E;
  134.  
  135.             memcpy(arp.shwaddr,iface->hwaddr,at->hwalen);
  136.             arp.tprotaddr = arp.sprotaddr;
  137.             arp.sprotaddr = iface->addr;
  138.             arp.opcode = ARP_REPLY;
  139.             if((bp = htonarp(&arp)) == NULLBUF)
  140.                 return;
  141.  
  142.             if(iface->forw != NULLIF)
  143.                 (*iface->forw->output)(iface->forw,
  144.                  arp.thwaddr,iface->forw->hwaddr,at->arptype,bp);
  145.             else
  146.                 (*iface->output)(iface,arp.thwaddr,
  147.                  iface->hwaddr,at->arptype,bp);
  148.             Arp_stat.inreq++;
  149.         } else {
  150.             Arp_stat.replies++;
  151.         }
  152.     } else if(arp.opcode == ARP_REQUEST
  153.      && (ap = arp_lookup(arp.hardware,arp.tprotaddr)) != NULLARP
  154.      && ap->pub){
  155.         /* Otherwise, respond if the guy he's looking for is
  156.          * published in our table.
  157.          */
  158.         memcpy(arp.thwaddr,arp.shwaddr,(int16)uchar(arp.hwalen));
  159.         memcpy(arp.shwaddr,ap->hw_addr,at->hwalen);
  160.         arp.tprotaddr = arp.sprotaddr;
  161.         arp.sprotaddr = ap->ip_addr;
  162.         arp.opcode = ARP_REPLY;
  163.         if((bp = htonarp(&arp)) == NULLBUF)
  164.             return;
  165.         if(iface->forw != NULLIF)
  166.             (*iface->forw->output)(iface->forw,
  167.              arp.thwaddr,iface->forw->hwaddr,at->arptype,bp);
  168.         else
  169.             (*iface->output)(iface,arp.thwaddr,
  170.              iface->hwaddr,at->arptype,bp);
  171.         Arp_stat.inreq++;
  172.     } else if(arp.opcode == REVARP_REQUEST){
  173.         for(i=0;i<HASHMOD;i++)
  174.             for(ap = Arp_tab[i];ap != NULLARP;ap = ap->next)
  175.                 if(memcmp(ap->hw_addr,arp.thwaddr,at->hwalen) == 0)
  176.                     goto found;
  177.     found:  if(ap != NULLARP && ap->pub){
  178.             memcpy(arp.shwaddr,iface->hwaddr,at->hwalen);
  179.             arp.tprotaddr = ap->ip_addr;
  180.             arp.sprotaddr = iface->addr;
  181.             arp.opcode = REVARP_REPLY;
  182.             if((bp = htonarp(&arp)) == NULLBUF)
  183.                 return;
  184.             if(iface->forw != NULLIF)
  185.                 (*iface->forw->output)(iface->forw,
  186.                  arp.thwaddr,iface->forw->hwaddr,REVARP_TYPE,bp);
  187.             else
  188.                 (*iface->output)(iface,arp.thwaddr,
  189.                  iface->hwaddr,REVARP_TYPE,bp);
  190.             Arp_stat.inreq++;
  191.         }
  192.     }
  193. }
  194. /* Add an IP-addr / hardware-addr pair to the ARP table */
  195. struct arp_tab *
  196. arp_add(ipaddr,hardware,hw_addr,pub)
  197. int32 ipaddr;           /* IP address, host order */
  198. int16 hardware;         /* Hardware type */
  199. char *hw_addr;          /* Hardware address, if known; NULLCHAR otherwise */
  200. int pub;                /* Publish this entry? */
  201. {
  202.     struct mbuf *bp;
  203.     register struct arp_tab *ap;
  204.     struct arp_type *at;
  205.     unsigned hashval;
  206.  
  207.     if(hardware >=NHWTYPES)
  208.         return NULLARP; /* Invalid hardware type */
  209.     at = &Arp_type[hardware];
  210.  
  211.     if((ap = arp_lookup(hardware,ipaddr)) == NULLARP){
  212.         /* New entry */
  213.         ap = (struct arp_tab *)callocw(1,sizeof(struct arp_tab));
  214.         ap->hw_addr = mallocw(at->hwalen);
  215.         ap->timer.func = arp_drop;
  216.         ap->timer.arg = ap;
  217.         ap->hardware = hardware;
  218.         ap->ip_addr = ipaddr;
  219.  
  220.         /* Put on head of hash chain */
  221.         hashval = hash_ip(ipaddr);
  222.         ap->prev = NULLARP;
  223.         ap->next = Arp_tab[hashval];
  224.         Arp_tab[hashval] = ap;
  225.         if(ap->next != NULLARP){
  226.             ap->next->prev = ap;
  227.         }
  228.     }
  229.     if(hw_addr == NULLCHAR){
  230.         /* Await response */
  231.         ap->state = ARP_PENDING;
  232.         set_timer(&ap->timer,Arp_type[hardware].pendtime * 1000L);
  233.     } else {
  234.         /* Response has come in, update entry and run through queue */
  235.         ap->state = ARP_VALID;
  236.         set_timer(&ap->timer,ARPLIFE*1000L);
  237.         memcpy(ap->hw_addr,hw_addr,at->hwalen);
  238.         ap->pub = pub;
  239.         arp_savefile();
  240.         while((bp = dequeue(&ap->pending)) != NULLBUF)
  241.             ip_route(NULLIF,bp,0);
  242.     }
  243.     start_timer(&ap->timer);
  244.     return ap;
  245. }
  246.  
  247. /* Remove an entry from the ARP table */
  248. void
  249. arp_drop(p)
  250. void *p;
  251. {
  252.     register struct arp_tab *ap;
  253.  
  254.     ap = (struct arp_tab *)p;
  255.     if(ap == NULLARP)
  256.         return;
  257.     stop_timer(&ap->timer); /* Shouldn't be necessary */
  258.     if(ap->next != NULLARP)
  259.         ap->next->prev = ap->prev;
  260.     if(ap->prev != NULLARP)
  261.         ap->prev->next = ap->next;
  262.     else
  263.         Arp_tab[hash_ip(ap->ip_addr)] = ap->next;
  264.     free_q(&ap->pending);
  265.     free(ap->hw_addr);
  266.     free((char *)ap);
  267. }
  268.  
  269. /* Look up the given IP address in the ARP table */
  270. struct arp_tab *
  271. arp_lookup(hardware,ipaddr)
  272. int16 hardware;
  273. int32 ipaddr;
  274. {
  275.     register struct arp_tab *ap;
  276.  
  277.     arp_loadfile();
  278.     for(ap = Arp_tab[hash_ip(ipaddr)]; ap != NULLARP; ap = ap->next){
  279.         if(ap->ip_addr == ipaddr && ap->hardware == hardware)
  280.             break;
  281.     }
  282.     return ap;
  283. }
  284. /* Send an ARP request to resolve IP address target_ip */
  285. static void
  286. arp_output(iface,hardware,target)
  287. struct iface *iface;
  288. int16 hardware;
  289. int32 target;
  290. {
  291.     struct arp arp;
  292.     struct mbuf *bp;
  293.     struct arp_type *at;
  294.  
  295.     at = &Arp_type[hardware];
  296.     if(iface->output == NULLFP)
  297.         return;
  298.  
  299.     arp.hardware = hardware;
  300.     arp.protocol = at->iptype;
  301.     arp.hwalen = at->hwalen;
  302.     arp.pralen = sizeof(int32);
  303.     arp.opcode = ARP_REQUEST;
  304.     memcpy(arp.shwaddr,iface->hwaddr,at->hwalen);
  305.     arp.sprotaddr = iface->addr;
  306.     memset(arp.thwaddr,0,at->hwalen);
  307.     arp.tprotaddr = target;
  308.     if((bp = htonarp(&arp)) == NULLBUF)
  309.         return;
  310.     (*iface->output)(iface,at->bdcst,
  311.         iface->hwaddr,at->arptype,bp);
  312.     Arp_stat.outreq++;
  313. }
  314.  
  315.